//
//  ACCipherTools.m
//  ACFramework
//
//  Created by caoyq on 2018/8/1.
//

#import "ACCipherTools.h"
#import <CommonCrypto/CommonCrypto.h>

@interface ACCipherTools()

@property (nonatomic, assign) CCOperation crypt;
@property (nonatomic, assign) uint32_t algorithm;
@property (nonatomic, assign) int keySize;
@property (nonatomic, assign) int blockSize;

@end

@implementation ACCipherTools

+ (instancetype)instance
{
    static ACCipherTools *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

#pragma mark - AES

- (id)aes_encryptValue: (id)value key: (NSString *)aKey iv: (NSData *)iv
{
    self.crypt = kCCEncrypt;
    self.algorithm = kCCAlgorithmAES;
    self.keySize = kCCKeySizeAES128;
    self.blockSize = kCCBlockSizeAES128;
    
    return [self encryptValue:value key:aKey iv:iv];
}

- (id)aes_decryptValue: (id)value key: (NSString *)aKey iv: (NSData *)iv
{
    self.crypt = kCCDecrypt;
    self.algorithm = kCCAlgorithmAES;
    self.keySize = kCCKeySizeAES128;
    self.blockSize = kCCBlockSizeAES128;
    
    return [self decryptValue:value key:aKey iv:iv];
}

#pragma mark - DES

- (id)des_encryptValue: (id)value key: (NSString *)aKey iv: (NSData *)iv
{
    self.crypt = kCCEncrypt;
    self.algorithm = kCCAlgorithmDES;
    self.keySize = kCCKeySizeDES;
    self.blockSize = kCCBlockSizeDES;
    
    return [self encryptValue:value key:aKey iv:iv];
}

- (id)des_decryptValue: (id)value key: (NSString *)aKey iv: (NSData *)iv
{
    self.crypt = kCCDecrypt;
    self.algorithm = kCCAlgorithmDES;
    self.keySize = kCCKeySizeDES;
    self.blockSize = kCCBlockSizeDES;
    
    return [self decryptValue:value key:aKey iv:iv];
}

#pragma mark - private

///公共的加密方法总结
- (id)encryptValue: (id)value key: (NSString *)aKey iv: (NSData *)iv
{
    BOOL isString = [value isKindOfClass:[NSString class]];
    
    NSData *data = nil;
    if (isString) {
        data = [value dataUsingEncoding:NSUTF8StringEncoding];
    }else {
        data = value;
    }
    
    NSData *result = [self handleData:data key:aKey iv:nil];
    
    if (isString) {
        return [result base64EncodedStringWithOptions:0];
    }
    return result;
}

///公共的解密方法总结
- (id)decryptValue: (id)value key: (NSString *)aKey iv: (NSData *)iv
{
    BOOL isString = [value isKindOfClass:[NSString class]];
    
    NSData *data = nil;
    if (isString) {
        data = [[NSData alloc] initWithBase64EncodedString:value options:0];
    }else {
        data = value;
    }
    
    NSData *result = [self handleData:data key:aKey iv:nil];
    
    if (isString) {
        return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
    }
    return result;
}

///公共的加解密基础方法
- (NSData *)handleData: (NSData *)data key: (NSString *)aKey iv:(NSData *)iv
{
    // 设置秘钥
    NSData *keyData = [aKey dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t cKey[self.keySize];
    bzero(cKey, sizeof(cKey));
    [keyData getBytes:cKey length:self.keySize];
    
    // 设置iv
    uint8_t cIv[self.blockSize];
    bzero(cIv, self.blockSize);
    int option = 0;
    if (iv) {   //des - cbc
        [iv getBytes:cIv length:self.blockSize];
        option = kCCOptionPKCS7Padding;
    } else {
        option = kCCOptionPKCS7Padding | kCCOptionECBMode;
    }
    
    // 设置输出缓冲区
    size_t bufferSize = [data length] + self.blockSize;
    void *buffer = malloc(bufferSize);
    
    // 开始加/解密
    size_t resultSize = 0;
    CCCryptorStatus cryptStatus = CCCrypt(self.crypt,
                                          self.algorithm,
                                          option,
                                          cKey,
                                          self.keySize,
                                          cIv,
                                          [data bytes],
                                          [data length],
                                          buffer,
                                          bufferSize,
                                          &resultSize);
    
    NSData *result = nil;
    if (cryptStatus == kCCSuccess) {
        result = [NSData dataWithBytesNoCopy:buffer length:resultSize];
    } else {
        free(buffer);
    }
    return result;
}

@end
